﻿using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace PVReportDeployer
{
    /// <summary>
    /// Interaction logic for ChooseSource.xaml
    /// </summary>
    public partial class ChooseSource : Page
    {

        /// <summary>
        /// Represents path information of PowerView report.
        /// </summary>
        private class PVItem
        {
            public string itemName { get; set; }
            public string sourcePath { get; set; }
            public string sourceUrl { get; set; }
            public string destUrl { get; set; }
            public string tmpPath { get; set; }
            public bool isProcessed { get; set; }
            public string deployFileName { get; set; }
            public PVItem()
            {
                isProcessed = false;
            }
        }
        /// <summary>
        /// TMP folder path.
        /// </summary>
        private string tmpFolder;
        /// <summary>
        /// TMP deploy folder path.
        /// </summary>
        private string tmpDeployFolder;
        /// <summary>
        /// TMP download folder Path.
        /// </summary>
        private string tmpDownloadFolder;
        /// <summary>
        /// Powerview report items.
        /// </summary>
        private List<PVItem> items;
        /// <summary>
        /// Selected item to edit.
        /// </summary>
        private PVItem selectedItem;

        public ChooseSource()
        {
            InitializeComponent();
            this.tmpFolder = System.IO.Path.GetTempPath() + "PVReportExtracted" + System.IO.Path.DirectorySeparatorChar;
            this.tmpDeployFolder = System.IO.Path.GetTempPath() +"PVReportDeploy" + System.IO.Path.DirectorySeparatorChar;
            this.tmpDownloadFolder = System.IO.Path.GetTempPath() + "PVReportDownload" + System.IO.Path.DirectorySeparatorChar;
        }

        /// <summary>
        /// Load from Local.
        /// </summary>
        private void LoadFromLocalBtn_Click(object sender, RoutedEventArgs e)
        {
            var chooser = new System.Windows.Forms.FolderBrowserDialog();
            if (chooser.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                this.sourceLoc.Text = chooser.SelectedPath;
                loadPVItems();
            }
        }

        /// <summary>
        /// Load from SharePoint.
        /// </summary>
        private void LoadFromSharePointBtn_Click(object sender, RoutedEventArgs e)
        {
            DownloadPVWindow loadFromSPWin = new DownloadPVWindow();
            if (loadFromSPWin.ShowDialog() == true)
            {
                this.sourceLoc.Text = this.tmpDownloadFolder;
                loadPVItems();
            }

        }
        /// <summary>
        /// Deploy to Local folder.
        /// </summary>
        private void DeployToLocalBtn_Click(object sender, RoutedEventArgs e)
        {
            var chooser = new System.Windows.Forms.FolderBrowserDialog();
            if (chooser.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                // deploy to tmp
                deployPVItems();


                // copy to dest
                try
                {
                    string destFoler = chooser.SelectedPath;
                    foreach (var file in Directory.GetFiles(this.tmpDeployFolder))
                    {
                        File.Copy(file, System.IO.Path.Combine(destFoler, System.IO.Path.GetFileName(file)), true);
                    }

                    // done
                    this.indicator.Visibility = Visibility.Visible;
                }
                catch (Exception err)
                {
                    MessageBox.Show(err.Message, "Deploy to local failed !");
                }

            }
        }
        /// <summary>
        /// Deploy to SharePoint folder.
        /// </summary>
        private void DeployToSPBtn_Click(object sender, RoutedEventArgs e)
        {
            deployPVItems();

            // open sharepoint configure window
            UploadPVWindow uploadToSPWin = new UploadPVWindow();
            if (uploadToSPWin.ShowDialog() == true)
            {
                // done
                this.indicator.Visibility = Visibility.Visible;
            }
        }
        /// <summary>
        /// List item selected.
        /// </summary>
        private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            ListBox lb = (sender as ListBox);
            if (lb.Items.Count == 0) return;
            string name = lb.SelectedValue as string;

            PVItem item = (from pvitem in items
                           where pvitem.itemName == name
                           select pvitem).First();
            this.selectedItem = item;
            if (!item.isProcessed)
            {
                // extract to tmp folder
                item.tmpPath = tmpFolder + item.itemName + System.IO.Path.DirectorySeparatorChar;
                ZipFile.ExtractToDirectory(item.sourcePath,  item.tmpPath);
                extractPVSource(item);
                item.isProcessed = true;
                this.fromDS.Text = item.sourceUrl;
                this.toDS.Text = item.destUrl;
                this.deployFileName.Text = item.deployFileName;
            }
            else
            {
                this.fromDS.Text = item.sourceUrl;
                this.toDS.Text = item.destUrl;
                this.deployFileName.Text = item.deployFileName;
            }
        }
        /// <summary>
        /// ToDS field edit.
        /// </summary>
        private void ToDS_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (this.selectedItem == null) return;
            this.selectedItem.destUrl = this.toDS.Text;
        }
        /// <summary>
        /// DeployFileName field edit.
        /// </summary>
        private void DeployFileName_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (this.selectedItem == null) return;
            this.selectedItem.deployFileName = this.deployFileName.Text;
        }

        // load local rdlx items
        private void loadPVItems()
        {
            if (this.sourceLoc.Text.Trim() == "") return;
            string[] filePaths = Directory.GetFiles(this.sourceLoc.Text, "*.rdlx");

            // clear UI
            this.fromDS.Text = null;
            this.toDS.Text = null;
            this.deployFileName.Text = null;
            this.indicator.Visibility = Visibility.Collapsed;
            // clear tmp folder
            if (Directory.Exists(tmpFolder))
            {
                System.IO.DirectoryInfo directory = new System.IO.DirectoryInfo(tmpFolder);
                foreach (System.IO.FileInfo file in directory.GetFiles()) file.Delete();
                foreach (System.IO.DirectoryInfo subDirectory in directory.GetDirectories()) subDirectory.Delete(true);
            }
            else
            {
                Directory.CreateDirectory(tmpFolder);
            }
            // create a deploy folder
            Directory.CreateDirectory(this.tmpDeployFolder);

            items = new List<PVItem>();
            foreach (string file in filePaths)
            {
                PVItem item = new PVItem();
                item.sourcePath = file;
                item.itemName = System.IO.Path.GetFileName(file);
                item.deployFileName = item.itemName;
                items.Add(item);
            }
            this.listBox.Items.Clear();
            this.selectedItem = null;
            foreach (PVItem item in items)
            {
                this.listBox.Items.Add(item.itemName);
            }
        }
        // deploy PV items to TMP deploy folder.
        private void deployPVItems()
        {
            // clear tmp folder
            System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(this.tmpDeployFolder);
            foreach (System.IO.FileInfo file in dir.GetFiles()) file.Delete();

            // zip to tmp
            foreach (PVItem item in items)
            {
                if (item.destUrl != null && item.destUrl.Trim() != "")
                {
                    updatePVSource(item);
                    // zip to destination
                    using (Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile())
                    {
                        zip.AddDirectory(item.tmpPath);
                        zip.Save(tmpDeployFolder + item.deployFileName);
                    }
                }
            }
        }
        // extract DataSourceReference
        private void extractPVSource(PVItem item) 
        {
            string path = item.tmpPath
                + "Reports"
                + System.IO.Path.DirectorySeparatorChar
                + "report.rdl";
            string file = File.ReadAllText(path);
            int start = file.IndexOf("<DataSourceReference>") + 21;
            int end = file.IndexOf("</DataSourceReference>");
            string pvsource = file.Substring(start, end - start);
            item.sourceUrl = pvsource;
        }
        // update DataSourceReference
        private void updatePVSource(PVItem item)
        {
            string path = item.tmpPath
                + System.IO.Path.DirectorySeparatorChar
                + "Reports"
                + System.IO.Path.DirectorySeparatorChar
                + "report.rdl";
            string file = File.ReadAllText(path);
            file = file.Replace(item.sourceUrl, item.destUrl);
            File.WriteAllText(path, file);
        }
    }
}
